package com.jming.jike.service.front.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jming.jike.common.BusinessException;
import com.jming.jike.common.PageResult;
import com.jming.jike.config.MybatisPlusConfig;
import com.jming.jike.dto.front.PayDTO;
import com.jming.jike.entity.AddressBook;
import com.jming.jike.entity.OrderDetail;
import com.jming.jike.entity.Orders;
import com.jming.jike.entity.OrdersDetail;
import com.jming.jike.mapper.AddressBookMapper;
import com.jming.jike.mapper.OrdersMapper;
import com.jming.jike.service.front.FrontOrdersService;
import com.jming.jike.service.front.OrderDetailService;
import com.jming.jike.service.front.ShoppingCartService;
import com.jming.jike.util.CopyBeanUtils;
import com.jming.jike.util.IdWorker;
import com.jming.jike.util.RedisUtil;
import com.jming.jike.vo.front.OrderDetailVO;
import com.jming.jike.vo.front.OrdersDetailVO;
import com.jming.jike.vo.front.ShoppingCartDetailVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author jinming.zhang
 * @version 0.0.1
 * @date 2022/05/10
 */
@Service
public class FrontOrdersServiceImpl implements FrontOrdersService {

    @Resource
    private OrdersMapper ordersMapper;

    @Resource
    private OrderDetailService orderDetailService;

    @Resource
    private AddressBookMapper addressBookMapper;

    @Resource
    private IdWorker idWorker;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private ShoppingCartService shoppingCartService;

    @Resource
    private MybatisPlusConfig mybatisPlusConfig;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createOrders() {

        String key = "createOrders_" + mybatisPlusConfig.getOperId();
        // 1.查询redis中是否存在当前用户未支付的订单, 如果存在则不可创建订单
        // 2.查询数据库中是否存在未支付的订单信息, 如果存在则不可创建订单
        if (redisUtil.getObject(key, Orders.class) != null ||
                ordersMapper.selectOne(Wrappers.<Orders>lambdaQuery()
                        .eq(Orders::getUserId, mybatisPlusConfig.getOperId())
                        .eq(Orders::getStatus, 1)
                        .last("limit 1")) != null) {

            throw new BusinessException("存在未支付的订单, 请先支付或取消未支付的订单!");
        }

        // 生成订单号
        String orderId = String.valueOf(idWorker.nextId());

        // 查询用户购物车信息 如果购物车为空 则不可下单
        ShoppingCartDetailVO shoppingCartDetailVO = shoppingCartService.list();
        if (ObjectUtils.isEmpty(shoppingCartDetailVO)) {
            throw new BusinessException("购物车为空, 不可下单!");
        }

        // 查询用户默认地址
        AddressBook addressBook = addressBookMapper.selectOne(Wrappers.<AddressBook>lambdaQuery()
                .eq(AddressBook::getUserId, mybatisPlusConfig.getOperId())
                .eq(AddressBook::getIsDeleted, 0)
                .eq(AddressBook::getIsDefault, 1)
                .last("limit 1"));

        // 是否存在默认地址
        boolean existAdd = !ObjectUtils.isEmpty(addressBook);

        // 订单信息
        Orders orders = Orders.builder()
                .orderId(orderId)
                .status(1)
                .orderTime(new Date())
                .addressBookId(existAdd ? addressBook.getId() : null)
                .phone(existAdd ? addressBook.getPhone() : null)
                .address(existAdd ? addressBook.getDetail() : null)
                .consignee(existAdd ? addressBook.getConsignee() : null)
                .amount(shoppingCartDetailVO.getTotalAmount())
                .build();

        // 订单详情信息
        List<OrderDetail> orderDetailList = shoppingCartDetailVO.getShoppingCartVOList().stream().map(sc ->
                OrderDetail.builder()
                        .orderId(orderId)
                        .name(sc.getName())
                        .image(sc.getImageUrl())
                        .soleId(sc.getSoleId())
                        .desc(sc.getDesc())
                        .number(sc.getNumber())
                        .amount(sc.getAmount())
                        .build()).collect(Collectors.toList());

        // 添加订单信息并清空购物车
        if (ordersMapper.insert(orders) > 0
                && orderDetailService.saveBatch(orderDetailList)
                && shoppingCartService.clean()) {

            // 将订单数据放入redis中 默认15分钟失效
            redisUtil.setObjectWillThrow(key, orders);
        }

        // 返回订单id
        return orderId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String pay(PayDTO payDTO) {

        // 查询订单是否存在
        String key = "createOrders_" + mybatisPlusConfig.getOperId();
        Orders orders = redisUtil.getObject(key, Orders.class);
        String orderId = payDTO.getOrderId();

        // 如果缓存为空 取消订单
        if (orders == null) {

            // 查询数据库中是否存在未付款的订单
            orders = ordersMapper.selectOne(Wrappers.<Orders>lambdaQuery()
                    .eq(Orders::getOrderId, orderId)
                    .eq(Orders::getStatus, 1).last("limit 1"));
            if (ObjectUtils.isEmpty(orders)) {

                throw new BusinessException("订单超时未支付已被取消,请重新下单!");
            }

            // 如果当前时间 - 下单时间大于15分钟 则取消订单
            if ((System.currentTimeMillis() - orders.getOrderTime().getTime()) > (1000 * 60 * 15)) {
                // 取消订单
                ordersMapper.update(null, Wrappers.<Orders>lambdaUpdate()
                        .eq(Orders::getOrderId, orderId)
                        .eq(Orders::getStatus, 1)
                        .set(Orders::getStatus, 5));
                throw new BusinessException("订单超时未支付已被取消,请重新下单!");
            }
        }

        // 如果地址不存在或者非默认地址, 修改订单地址
        if (orders.getAddressBookId() == null || !payDTO.getAddressBookId().equals(orders.getAddressBookId())) {

            AddressBook addressBook = addressBookMapper.selectById(payDTO.getAddressBookId());
            orders.setAddressBookId(payDTO.getAddressBookId());
            orders.setPhone(addressBook.getPhone());
            orders.setAddress(addressBook.getDetail());
            orders.setConsignee(addressBook.getConsignee());
        }

        // 订单信息
        orders.setStatus(2);
        orders.setPayMethod(payDTO.getPayMethod());
        orders.setRemark(StringUtils.hasText(payDTO.getRemark()) ? payDTO.getRemark() : null);
        orders.setCheckoutTime(new Date());

        // 调用支付接口支付 TODO

        // 支付成功修改支付信息
        int update = ordersMapper.updateById(orders);

        // 支付成功 删除缓存
        if (update <= 0 || !redisUtil.queryDelete(key, Orders.class)) {
            // 如果支付成功 缓存删除失败 调用退款接口 退款 TODO

            throw new BusinessException("支付失败, 请返回重新支付!");
        }

        return orderId;
    }

    @Override
    public Boolean cancelOrder(String orderId) {

        // 取消订单
        String key = "createOrders_" + mybatisPlusConfig.getOperId();
        Long userId = mybatisPlusConfig.getOperId();
        int update = ordersMapper.update(null, Wrappers.<Orders>lambdaUpdate()
                .eq(Orders::getUserId, userId)
                .eq(Orders::getStatus, 1)
                .set(Orders::getStatus, 5));

        // 判断是否取消成功
        // 如果取消成功 则删除缓存
        if (update <= 0 || !redisUtil.queryDelete(key, Orders.class)) {

            throw new BusinessException("取消订单失败");
        }

        return true;
    }

    @Override
    public PageResult<OrdersDetailVO> pageOrders(Integer pageIndex, Integer pageSize) {

        // 分页查询订单信息
        Page<Orders> ordersPage = ordersMapper.selectPage(new Page<>(pageIndex, pageSize), Wrappers.<Orders>lambdaQuery()
                .eq(Orders::getUserId, mybatisPlusConfig.getOperId())
                .orderByAsc(Orders::getStatus)
                .orderByDesc(Orders::getOrderTime));

        if (ObjectUtils.isEmpty(ordersPage) || CollectionUtils.isEmpty(ordersPage.getRecords())) {

            return new PageResult<>(0, 0, 0, new ArrayList<>());
        }

        // 批量查询订单信息
        List<String> orderIdList = ordersPage.getRecords().stream().map(Orders::getOrderId).collect(Collectors.toList());
        List<OrderDetail> orderDetailList = orderDetailService.list(Wrappers.<OrderDetail>lambdaQuery()
                .in(OrderDetail::getOrderId, orderIdList));

        // 处理数据 添加订单详情数据
        List<OrdersDetailVO> detailVOList = ordersPage.getRecords().stream().map(o -> {

            // 订单
            OrdersDetailVO ordersDetailVO = CopyBeanUtils.copyBean(o, new OrdersDetailVO());

            // 订单详情
            List<OrderDetailVO> orderDetailVOList = new ArrayList<>();
            for (OrderDetail orderDetail : orderDetailList) {
                if (o.getOrderId().equals(orderDetail.getOrderId())) {
                    orderDetailVOList.add(CopyBeanUtils.copyBean(orderDetail, new OrderDetailVO()));
                }
            }
            ordersDetailVO.setOrderDetailVOList(orderDetailVOList);
            return ordersDetailVO;
        }).collect(Collectors.toList());

        return new PageResult<>((int) ordersPage.getCurrent(), (int) ordersPage.getSize(), (int) ordersPage.getTotal(), detailVOList);
    }

    @Override
    public OrdersDetailVO orderDetail(String orderId) {

        // 查询订单详情
        List<OrdersDetail> ordersDetailList = ordersMapper.queryOrdersDetail(orderId);

        OrdersDetailVO ordersDetailVO = new OrdersDetailVO();
        if (CollectionUtils.isEmpty(ordersDetailList)) {
            return ordersDetailVO;
        }

        ordersDetailVO = CopyBeanUtils.copyBean(ordersDetailList.get(0), ordersDetailVO);

        // 订单详细
        ordersDetailVO.setOrderDetailVOList(ordersDetailList.stream().map(odl -> {
            OrderDetailVO orderDetailVO = CopyBeanUtils.copyBean(odl, new OrderDetailVO());
            orderDetailVO.setId(odl.getDetailId());
            orderDetailVO.setAmount(odl.getDetailAmount());
            return orderDetailVO;
        }).collect(Collectors.toList()));

        return ordersDetailVO;
    }
}
